package com.magnificent.panda.ui;

import com.magnificent.graph.io.mxCodec;
import com.magnificent.graph.model.*;
import com.magnificent.graph.util.mxEvent;
import com.magnificent.graph.util.mxEventObject;
import com.magnificent.graph.util.mxEventSource.mxIEventListener;
import com.magnificent.graph.util.mxPoint;
import com.magnificent.graph.util.mxUtils;
import com.magnificent.graph.view.mxCellState;
import com.magnificent.graph.view.mxGraph;
import com.magnificent.panda.resources.Resources;
import com.magnificent.panda.ui.editor.BasicGraphEditor;
import com.magnificent.panda.ui.editor.EditorPalette;
import com.magnificent.panda.ui.util.mxGraphTransferable;
import com.magnificent.panda.utils.PandaConstants;
import org.w3c.dom.Document;

import javax.swing.*;
import java.awt.*;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.net.URL;
import java.text.NumberFormat;
import java.util.Iterator;
import java.util.List;

public class GraphEditor extends BasicGraphEditor {
    private static final long serialVersionUID = -4601740824088314699L;

    private static JFrame graphFrame;
    private static GraphEditor graphEditor;

    /**
     * Holds the shared number formatter.
     *
     * @see NumberFormat#getInstance()
     */
    public static final NumberFormat numberFormat = NumberFormat.getInstance();

    /**
     * Holds the URL for the icon to be used as a handle for creating new
     * connections. This is currently unused.
     */
    public static URL url = null;

    //GraphEditor.class.getResource("/com/magnificent/panda/ui/images/connector.gif");

    public GraphEditor() {
        this(PandaConstants.PANDA_TITLE, new CustomGraphComponent(new CustomGraph()));
    }

    public GraphEditor(String appTitle, GraphComponent component) {
        super(appTitle, component);
        graphEditor = this;

        final mxGraph graph = graphComponent.getGraph();

        Paper paper = new Paper();
        paper.setSize(paper.getWidth() * 1.2, paper.getHeight() * 1.2);

        PageFormat pageFormat = new PageFormat();
        pageFormat.setOrientation(PageFormat.LANDSCAPE);
        pageFormat.setPaper(paper);

        graphComponent.setPageFormat(pageFormat);

        // Creates the shapes palette
        EditorPalette shapesPalette = insertPalette("Элементы");
//        EditorPalette imagesPalette = insertPalette(mxResources.get("images"));
//        EditorPalette symbolsPalette = insertPalette(mxResources.get("symbols"));

        // Sets the edge template to be used for creating new edges if an edge
        // is clicked in the shape palette
        shapesPalette.addListener(mxEvent.SELECT, new mxIEventListener() {
            public void invoke(Object sender, mxEventObject evt) {
                Object tmp = evt.getProperty("transferable");

                if (tmp instanceof mxGraphTransferable) {
                    mxGraphTransferable t = (mxGraphTransferable) tmp;
                    Object cell = t.getCells()[0];

                    if (graph.getModel().isEdge(cell)) {
                        ((CustomGraph) graph).setEdgeTemplate(cell);
                    }
                }
            }

        });

        // Adds some template cells for dropping into the graph
        /*   shapesPalette
.addTemplate(
"Контэйнер",
new ImageIcon(
        GraphEditor.class
                .getResource("/com/magnificent/panda/ui/images/swimlane.png")),
"swimlane", 280, 280, "Container");
shapesPalette
.addTemplate(
"Прямоугольник",
new ImageIcon(
        GraphEditor.class
                .getResource("/com/magnificent/panda/ui/images/rectangle.png")),
null, 160, 120, "");
shapesPalette
.addTemplate(
"Округлый прямоугольник",
new ImageIcon(
        GraphEditor.class
                .getResource("/com/magnificent/panda/ui/images/rounded.png")),
"rounded=1", 160, 120, "");
shapesPalette
.addTemplate(
"Эллипс",
new ImageIcon(
        GraphEditor.class
                .getResource("/com/magnificent/panda/ui/images/ellipse.png")),
"ellipse", 160, 160, "");
shapesPalette
.addTemplate(
"Двойной эллипс",
new ImageIcon(
        GraphEditor.class
                .getResource("/com/magnificent/panda/ui/images/doubleellipse.png")),
"ellipse;shape=doubleEllipse", 160, 160, "");
shapesPalette
.addTemplate(
"Треугольник",
new ImageIcon(
        GraphEditor.class
                .getResource("/com/magnificent/panda/ui/images/triangle.png")),
"triangle", 120, 160, "");
shapesPalette
.addTemplate(
"Ромб",
new ImageIcon(
        GraphEditor.class
                .getResource("/com/magnificent/panda/ui/images/rhombus.png")),
"rhombus", 160, 160, "");
shapesPalette
.addTemplate(
"Горизонтальная линия",
new ImageIcon(
        GraphEditor.class
                .getResource("/com/magnificent/panda/ui/images/hline.png")),
"line", 160, 10, "");
shapesPalette
.addTemplate(
"Шестиугольник",
new ImageIcon(
        GraphEditor.class
                .getResource("/com/magnificent/panda/ui/images/hexagon.png")),
"shape=hexagon", 160, 120, "");
shapesPalette
.addTemplate(
"Цилиндр",
new ImageIcon(
        GraphEditor.class
                .getResource("/com/magnificent/panda/ui/images/cylinder.png")),
"shape=cylinder", 120, 160, "");     */
        shapesPalette.addTemplate("Пользователь", new ImageIcon(GraphEditor.class
                .getResource("/com/magnificent/panda/ui/images/actor.png")),
                "shape=actor", 45, 60, "Пользователь", CellRole.ACTOR);
        shapesPalette.addTemplate("ИКФ", new ImageIcon(GraphEditor.class
                .getResource("/com/magnificent/panda/ui/images/cloud.png")),
                "ellipse;shape=cloud", 60, 45, "Корреляционная\nфункция", CellRole.CORRELATION_FUNCTION);
        /*
shapesPalette
.addEdgeTemplate(
      "Straight",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/straight.png")),
      "straight", 120, 120, "");
shapesPalette
.addEdgeTemplate(
      "Horizontal Connector",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/connect.png")),
      null, 100, 100, "");
shapesPalette
.addEdgeTemplate(
      "Vertical Connector",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/vertical.png")),
      "vertical", 100, 100, "");
shapesPalette
.addEdgeTemplate(
      "Entity Relation",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/entity.png")),
      "entity", 100, 100, "");
shapesPalette.addEdgeTemplate("Arrow", new ImageIcon(GraphEditor.class
.getResource("/com/magnificent/panda/ui/images/arrow.png")),
"arrow", 120, 120, "");

imagesPalette.addTemplate("Bell", new ImageIcon(GraphEditor.class
.getResource("/com/magnificent/panda/ui/images/bell.png")),
"image;image=/com/magnificent/panda/ui/images/bell.png", 50,
50, "Bell");
imagesPalette.addTemplate("Box", new ImageIcon(GraphEditor.class
.getResource("/com/magnificent/panda/ui/images/box.png")),
"image;image=/com/magnificent/panda/ui/images/box.png", 50,
50, "Box");
imagesPalette
.addTemplate(
      "Cube",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/cube_green.png")),
      "image;image=/com/magnificent/panda/ui/images/cube_green.png",
      50, 50, "Cube");
imagesPalette
.addTemplate(
      "User",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/dude3.png")),
      "roundImage;image=/com/magnificent/panda/ui/images/dude3.png",
      50, 50, "User");
imagesPalette
.addTemplate(
      "Earth",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/earth.png")),
      "roundImage;image=/com/magnificent/panda/ui/images/earth.png",
      50, 50, "Earth");
imagesPalette.addTemplate("Gear", new ImageIcon(GraphEditor.class
.getResource("/com/magnificent/panda/ui/images/gear.png")),
"roundImage;image=/com/magnificent/panda/ui/images/gear.png",
50, 50, "Gear");
imagesPalette.addTemplate("Home", new ImageIcon(GraphEditor.class
.getResource("/com/magnificent/panda/ui/images/house.png")),
"image;image=/com/magnificent/panda/ui/images/house.png", 50,
50, "Home");
imagesPalette
.addTemplate(
      "Package",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/package.png")),
      "image;image=/com/magnificent/panda/ui/images/package.png",
      50, 50, "Package");
imagesPalette
.addTemplate(
      "Printer",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/printer.png")),
      "image;image=/com/magnificent/panda/ui/images/printer.png",
      50, 50, "Printer");
imagesPalette.addTemplate("Server", new ImageIcon(GraphEditor.class
.getResource("/com/magnificent/panda/ui/images/server.png")),
"image;image=/com/magnificent/panda/ui/images/server.png",
50, 50, "Server");
imagesPalette
.addTemplate(
      "Workplace",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/workplace.png")),
      "image;image=/com/magnificent/panda/ui/images/workplace.png",
      50, 50, "Workplace");
imagesPalette
.addTemplate(
      "Wrench",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/wrench.png")),
      "roundImage;image=/com/magnificent/panda/ui/images/wrench.png",
      50, 50, "Wrench");

symbolsPalette
.addTemplate(
      "Cancel",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/cancel_end.png")),
      "roundImage;image=/com/magnificent/panda/ui/images/cancel_end.png",
      80, 80, "Cancel");
symbolsPalette
.addTemplate(
      "Error",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/error.png")),
      "roundImage;image=/com/magnificent/panda/ui/images/error.png",
      80, 80, "Error");
symbolsPalette
.addTemplate(
      "Event",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/event.png")),
      "roundImage;image=/com/magnificent/panda/ui/images/event.png",
      80, 80, "Event");
symbolsPalette
.addTemplate(
      "Fork",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/fork.png")),
      "rhombusImage;image=/com/magnificent/panda/ui/images/fork.png",
      80, 80, "Fork");
symbolsPalette
.addTemplate(
      "Inclusive",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/inclusive.png")),
      "rhombusImage;image=/com/magnificent/panda/ui/images/inclusive.png",
      80, 80, "Inclusive");
symbolsPalette.addTemplate("Link", new ImageIcon(GraphEditor.class
.getResource("/com/magnificent/panda/ui/images/link.png")),
"roundImage;image=/com/magnificent/panda/ui/images/link.png",
80, 80, "Link");
symbolsPalette
.addTemplate(
      "Merge",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/merge.png")),
      "rhombusImage;image=/com/magnificent/panda/ui/images/merge.png",
      80, 80, "Merge");
symbolsPalette
.addTemplate(
      "Message",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/message.png")),
      "roundImage;image=/com/magnificent/panda/ui/images/message.png",
      80, 80, "Message");
symbolsPalette
.addTemplate(
      "Multiple",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/multiple.png")),
      "roundImage;image=/com/magnificent/panda/ui/images/multiple.png",
      80, 80, "Multiple");
symbolsPalette.addTemplate("Rule", new ImageIcon(GraphEditor.class
.getResource("/com/magnificent/panda/ui/images/rule.png")),
"roundImage;image=/com/magnificent/panda/ui/images/rule.png",
80, 80, "Rule");
symbolsPalette
.addTemplate(
      "Terminate",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/terminate.png")),
      "roundImage;image=/com/magnificent/panda/ui/images/terminate.png",
      80, 80, "Terminate");
symbolsPalette
.addTemplate(
      "Timer",
      new ImageIcon(
              GraphEditor.class
                      .getResource("/com/magnificent/panda/ui/images/timer.png")),
      "roundImage;image=/com/magnificent/panda/ui/images/timer.png",
      80, 80, "Timer");*/
    }

    /**
     *
     */
    public static class CustomGraphComponent extends GraphComponent {

        /**
         *
         */
        private static final long serialVersionUID = -6833603133512882012L;

        /**
         * @param graph
         */
        public CustomGraphComponent(mxGraph graph) {
            super(graph);

            // Sets switches typically used in an editor
            setPageVisible(true);
            setGridVisible(true);
            setToolTips(true);
            getConnectionHandler().setCreateTarget(true);

            // Loads the defalt stylesheet from an external file
            mxCodec codec = new mxCodec();
            Document doc = mxUtils.loadDocument(GraphEditor.class.getResource(
                    "/com/magnificent/panda/ui/resources/default-style.xml")
                    .toString());
            codec.decode(doc.getDocumentElement(), graph.getStylesheet());

            // Sets the background to white
            getViewport().setOpaque(false);
            setBackground(Color.WHITE);
        }

        /**
         * Overrides drop behaviour to set the cell style if the target
         * is not a valid drop target and the cells are of the same
         * type (eg. both vertices or both edges).
         */
        public Object[] importCells(Object[] cells, double dx, double dy,
                                    Object target, Point location) {
            if (target == null && cells.length == 1 && location != null) {
                target = getCellAt(location.x, location.y);

                if (target instanceof mxICell && cells[0] instanceof mxICell) {
                    mxICell targetCell = (mxICell) target;
                    mxICell dropCell = (mxICell) cells[0];

                    if (targetCell.isVertex() == dropCell.isVertex()
                            || targetCell.isEdge() == dropCell.isEdge()) {
                        mxIGraphModel model = graph.getModel();
                        model.setStyle(target, model.getStyle(cells[0]));
                        graph.setSelectionCell(target);

                        return null;
                    }
                }
            }

            return super.importCells(cells, dx, dy, target, location);
        }

    }

    /**
     * A graph that creates new edges from a given template edge.
     */
    public static class CustomGraph extends mxGraph {
        /**
         * Holds the edge to be used as a template for inserting new edges.
         */
        protected Object edgeTemplate;

        /**
         * Custom graph that defines the alternate edge style to be used when
         * the middle control point of edges is double clicked (flipped).
         */
        public CustomGraph() {
            setAlternateEdgeStyle("edgeStyle=mxEdgeStyle.ElbowConnector;elbow=vertical");
        }

        /**
         * Sets the edge template to be used to inserting edges.
         */
        public void setEdgeTemplate(Object template) {
            edgeTemplate = template;
        }

        /**
         * Prints out some useful information about the cell in the tooltip.
         */
        public String getToolTipForCell(Object cell) {
            String tip = "<html>";
            mxGeometry geo = getModel().getGeometry(cell);
            mxCellState state = getView().getState(cell);

            if (getModel().isEdge(cell)) {
                tip += "points={";

                if (geo != null) {
                    List<mxPoint> points = geo.getPoints();

                    if (points != null) {
                        Iterator<mxPoint> it = points.iterator();

                        while (it.hasNext()) {
                            mxPoint point = it.next();
                            tip += "[x=" + numberFormat.format(point.getX())
                                    + ",y=" + numberFormat.format(point.getY())
                                    + "],";
                        }

                        tip = tip.substring(0, tip.length() - 1);
                    }
                }

                tip += "}<br>";
                tip += "absPoints={";

                if (state != null) {

                    for (int i = 0; i < state.getAbsolutePointCount(); i++) {
                        mxPoint point = state.getAbsolutePoint(i);
                        tip += "[x=" + numberFormat.format(point.getX())
                                + ",y=" + numberFormat.format(point.getY())
                                + "],";
                    }

                    tip = tip.substring(0, tip.length() - 1);
                }

                tip += "}";
            } else {
                tip += "geo=[";

                if (geo != null) {
                    tip += "x=" + numberFormat.format(geo.getX()) + ",y="
                            + numberFormat.format(geo.getY()) + ",width="
                            + numberFormat.format(geo.getWidth()) + ",height="
                            + numberFormat.format(geo.getHeight());
                }

                tip += "]<br>";
                tip += "state=[";

                if (state != null) {
                    tip += "x=" + numberFormat.format(state.getX()) + ",y="
                            + numberFormat.format(state.getY()) + ",width="
                            + numberFormat.format(state.getWidth())
                            + ",height="
                            + numberFormat.format(state.getHeight());
                }

                tip += "]";
            }

            mxPoint trans = getView().getTranslate();

            tip += "<br>scale=" + numberFormat.format(getView().getScale())
                    + ", translate=[x=" + numberFormat.format(trans.getX())
                    + ",y=" + numberFormat.format(trans.getY()) + "]";
            tip += "</html>";

            return tip;
        }

        /**
         * Overrides the method to use the currently selected edge template for
         * new edges.
         *
         * @param parent
         * @param id
         * @param value
         * @param source
         * @param target
         * @param style
         * @return
         */
        public Object createEdge(Object parent, String id, Object value,
                                 Object source, Object target, String style) {
            if (edgeTemplate != null) {
                Cell edge = (Cell) cloneCells(new Object[]{edgeTemplate})[0];
                edge.setId(id);

                return edge;
            }

            return super.createEdge(parent, id, value, source, target, style);
        }
    }



    public JFrame createFrame(JMenuBar menuBar) {
        graphFrame = new JFrame();
        graphFrame.getContentPane().add(this);
        graphFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        graphFrame.setJMenuBar(menuBar);
        graphFrame.setSize(1000, 750);
        graphFrame.setLocationRelativeTo(null);
        graphFrame.setIconImage(Resources.APP_ICON.getImage());

        // Updates the graphFrame title
        updateTitle();

        return graphFrame;
    }

    public static GraphEditor getGraphEditor() {
        return graphEditor;
    }

    public static void setGraphEditor(GraphEditor graphEditor) {
        GraphEditor.graphEditor = graphEditor;
    }

    public static JFrame getGraphFrame() {
        return graphFrame;
    }
}

  /* converted to utf8 */